#!/bin/bash

##########
# Config #
##########

IsTest=true

# (InstallAptPackage)
InstallPackage=InstallAptPackage

# (IsAptPackageInstalled)
IsPackageInstalled=IsAptPackageInstalled

#########
# Const #
#########

SUCCESS=0
IGNORED=204
EXCEPTION=-1
NOPARAM=noparam

#############
# Utilities #
#############

function Log
{
    color=$1
    shift
    tag=$1
    shift
    
    NO_COLOR='\033[0m'
    echo -e "${color}${tag} "$@"${NO_COLOR}"
}

function Info
{
    color='\033[0;30m' # Black
    tag=[Info]
    Log $color $tag $@
}

function Warning
{
    color='\033[0;36m' # Cyan
    tag=[Warning]
    Log $color $tag $@
}

function Error
{
    color='\033[0;31m' # Red
    tag=[Error]
    Log $color $tag $@
}

function AssertResult
{
    if [ $? != $SUCCESS ]
    then
        Error Failed: $@
        exit $EXCEPTION
    fi
}

function LogExecuteAssert
{
    cmdList=$@
    Info $cmdList

    # The "&&" and "||" does not work when in string variable
    # So need to split the cmd and execute one by one
    currentCmd=
    for cmd in ${cmdList[@]}
    do
        if [ $cmd == "&&" ]
        then
            # It's "and", need to execute cmd and check result
            $currentCmd
            AssertResult $currentCmd
            currentCmd=
        elif [ $cmd == "||" ]
        then
            # It's "or", do not need to check current result
            $currentCmd
            currentCmd=
        else
            # Combine cmd together
            currentCmd="$currentCmd $cmd"            
        fi
    done

    # The last cmd
    $currentCmd
    AssertResult $currentCmd
}

function ExecuteFunction
{
    func=$1

    Info Execute $func
    $func

    result=$?
    if [ $result == $SUCCESS ]
    then
        Info $func is successful
    elif [ $result == $IGNORED ]
    then
        Info $func is skipped
    else
        Error Execution Failed: $func
        exit $EXCEPTION
    fi
}

function IsCmdExist
{
    cmd=$1
    
    tmp=$(type $cmd > /dev/null 2>&1)
    result=$?
    echo $result
    return $result
}

function IsAptPackageInstalled
{
    pkg=$1
    
    apt list --installed | grep "$pkg" > /dev/null 2>&1
    result=$?
    echo $result
    return $result
}

function InstallAptPackage
{
    pkgName=$1

    cmd="sudo apt install -y $pkgName"
    LogExecuteAssert $cmd
}

function CheckCmdAndInstall
{
    cmd=$1
    pkgToInstall=$2

    if [ $(IsCmdExist $cmd) != $SUCCESS ]
    then
        $InstallPackage $pkgToInstall
    fi
}

function CheckPkgAndInstall
{
    pkg=$1
    pkgToInstall=$2

    if [ $($IsPackageInstalled $pkg) != $SUCCESS ]
    then
        $InstallPackage $pkgToInstall
    fi
}

function ConfigureBuildInstall
{
    # configCmd=$1
    # makeCmd=$2
    # installCmd=$3

    for i in $(seq 1 $#)
    do
        cmd=$1
        if [ "$cmd" != $NOPARAM ]
        then
            LogExecuteAssert $cmd
        fi
        
        shift
    done

    return $SUCCESS
}

function InstallFromGitLocalDir
{
    workDirName=$1
    version=$2
    configCmd=$3
    makeCmd=$4
    installCmd=$5
    
    cd $BaseDir
    cd $workDirName
    AssertResult cd $workDirName

    if [ $version != $NOPARAM ]
    then
        gitCheckoutCmd="git checkout $version"
        LogExecuteAssert $gitCheckoutCmd
    fi

    ConfigureBuildInstall "$configCmd" "$makeCmd" "$installCmd"
    
    return $?
}

function InstallFromGit
{
    gitPath=$1
    workDirName=$2
    version=$3
    configCmd=$4
    makeCmd=$5
    installCmd=$6

    cd $BaseDir
    if [ ! -d $workDirName ]
    then
        gitCloneCmd="git clone $gitPath"
        LogExecuteAssert $gitCloneCmd
        gitUpdateCmd="cd $workDirName && git submodule update --init --recursive"
        LogExecuteAssert $gitUpdateCmd
    fi

    InstallFromGitLocalDir "$workDirName" "$version" "$configCmd" "$makeCmd" "$installCmd"
    
    return $?
}

function InstallFromWebTar
{
    webPath=$1
    workDirName=$2
    configCmd=$3
    makeCmd=$4
    installCmd=$5

    pkgTarName=${webPath##*\/}
    pkgName=$workDirName

    cd $BaseDir
    if [ ! -d $pkgName ]
    then
        if [ ! -f $pkgTarName ]
        then
            cmd="wget $webPath"
            LogExecuteAssert $cmd
        fi
        tarCmd="tar -xvf $pkgTarName"
        LogExecuteAssert $tarCmd
    fi

    cd $BaseDir
    cd $workDirName
    AssertResult cd $workDirName
    ConfigureBuildInstall "$configCmd" "$makeCmd" "$installCmd"

    return $?
}

###################
# Build Functions #
###################

function Test
{
    Info I am Test
    
    return $SUCCESS
}

#############
# Run Build #
#############

BaseDir=$(pwd)
if [ $# == 1 ]
then
    if [ -d $1 ]
    then
        BaseDir=$1
    else
        Error Base dir $1 is not valid dir
        exit $EXCEPTION
    fi
fi
if [[ ! $BaseDir =~ ^/ ]]
then
    Error Base dir $BaseDir is not absolute path
    exit $EXCEPTION
fi

if [ $IsTest == true ]
then
    ExecuteFunction Test
fi
